package overall

import (
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	. "go_tempate/common/function"
	. "go_tempate/config"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"runtime/debug"
	"strings"
)

/*
 异常处理中间件

 作用：
  为所有接口的异常进行统一的返回处理
*/
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func GlobalException() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// 检查是否存在断开的连接，因为它实际上不是
				//保证进行紧急堆栈跟踪的条件。
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}
				httpRequest, _ := httputil.DumpRequest(ctx.Request, false)
				if brokenPipe {
					Logger.Error(ctx.Request.URL.Path,
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
					// 如果连接已断开，我们就无法向其写入状态。
					_ = ctx.Error(err.(error)) // 无：错误检查
					ctx.Abort()
					return
				}

				//判断是否对错误日志堆栈
				if Stack {
					Logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
						zap.String("stack", string(debug.Stack())),
					)
				} else {
					Logger.Error("[Recovery from panic]",
						zap.Any("error", err),
						zap.String("request", string(httpRequest)),
					)
				}

				ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "message": "发生错误"})
			}
		}()

		//执行后续中间件
		//--------------------------------------------------------------------------------------------------------------------------------------------------------------
		ctx.Next()
	}
}
